using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Html;
using System.Runtime.CompilerServices;
using Awaiter;
using Canvas.Scripts.ImageRotate;
using Nsb.Classes;
using ThemeChain;
using WhirliGigEdit.Classes;
using Yoshi.Classes;
using jQueryApi;

namespace WhirliGig.Classes
{
    [IgnoreNamespace]
    public class GigEdit : Gig, IFocusable // IFocusable needed by focusable assignment in menu dictionaries - no compile time linkages
    {
        public const string YourText = "-- double-click here to edit --";
        //private const string TestDefault = "https://docs.google.com/present/embed?id=dcxgm95h_820gm7svsdq&autoStart=true&loop=true&interval=7";
        //private static readonly RegularExpression RxDraggable = new RegularExpression(@"\s*ui-[^\s""']+", "g");

        public const string EmbeddedCodeType = "EmbeddedCode";
        public const string CoverBloatClass = "CoverBloat";
        private const string MaskOnClass = "MaskOn";
        private const string DotMaskOnClass = "." + MaskOnClass;

        //
        // When updading GigTypes also consider updating GigShow.CssMap
        //

        private static readonly Dictionary GigTypes =
            new Dictionary(
                "ClassItem", new Dictionary(
                                 "menus", new string[] {"colors:both", "border", "font", "layer", "copy", "groupify:<u>g</u>roupify", "zero", "remove", "cancel"}
                                 ),
                "TextItem", new Dictionary(
                                "menus", new string[] {"colors:both", "border", "font", "layer", "copy", "groupify:<u>g</u>roupify", "link", "zero", "remove", "cancel"}
                                ),
                "Button", new Dictionary(
                              "menus", new string[] {"colors:both", "border", "font", "layer", "copy", "groupify:<u>g</u>roupify", "zero", "remove", "cancel"}
                              ),
                "TextBox", new Dictionary(
                               "menus", new string[] {"colors:both", "border", "font", "layer", "copy", "groupify:<u>g</u>roupify", "zero", "remove", "cancel"}
                               ),
                "TextArea", new Dictionary(
                                "menus", new string[] {"colors:both", "border", "font", "layer", "copy", "groupify:<u>g</u>roupify", "zero", "remove", "cancel"}
                                ),
                "DropImage", new Dictionary(
                                 "menus", new string[] {"color:bg", "border", "layer", "copy", "groupify:<u>g</u>roupify", "link", "zero", "remove", "cancel"}
                                 ),
                "GoogleSlideShow", new Dictionary(
                                       "menus", new string[] {"border", "layer", "copy", "groupify:<u>g</u>roupify", "zero", "remove", "cancel"}
                                       ),
                "EmbeddedCode", new Dictionary(
                                    "menus", new string[] {"border", "layer", "copy", "groupify:<u>g</u>roupify", "zero", "remove", "cancel"}
                                    )
                )
                                           ;

        private static GigMu _gmu;

        public readonly GigShowEdit Editor;
        private readonly jQueryObject _snapToNone = (jQueryObject) Script.Literal("jQuery()");
        public jQueryObject Cover /*= jQuery.FromHtml("<div/>")*/; // Fill it with a dummy element so early operations on it don't throw exceptions.
        public jQueryObject CoverInner /*= jQuery.FromHtml("<div/>")*/;
        public bool QueSave;
        public jQueryObject TheGear /*= jQuery.FromHtml("<div/>")*/;
        private GigData _savedGig;
        private jQueryObject _snapToEl;
        private double _snapToH;
        private double[] _snapToPos;
        private double _snapToW;
        private int _xc;
        private int _yc;

        public GigEdit(GigShowEdit show)
        {
            TestInstance.AddInstance(this);
            Editor = show;

            Element.Data("gigEdit", this);

            //AddCover();
            //new Await().AddFn(AddCover).Commit();
            //Window.SetTimeout(AddCover, 500);
        }

        public GigData MyGd
        {
            get { return Editor.GigById(Id); }
        }

        public Dictionary MyCss
        {
            get
            {
                // ReSharper disable PossibleNullReferenceException
                Debug.Assert(MyGd.css != null);
                // ReSharper restore PossibleNullReferenceException
                return MyGd.css;
            }
        }

        #region Finders
        public static Gig GigGigByEl(jQueryObject el)
        {
            try
            {
                return (Gig) el.GetDataValue(GigClassName);
            }
            catch
            {
                return null;
            }
        }

        #endregion Finders

        #region IFocusable Members

        public void MarkItem(jQueryObject pie, Dictionary tst)
        {
            Dictionary d = (Dictionary) tst["item"];
            tst["prop"] = JGigHelpers.Prp(d, "prop", tst["prop"]);
            string prop = (string) tst["prop"];
            string tBool = (string) d["bool"];
            string tNotBool = (string) d["!bool"];

            if (tBool != null)
            {
                if ((bool) Type.GetField(MyGd, tBool))
                    pie.AddClass("Selected");
            }
            else if (tNotBool != null)
            {
                if (!(bool) Type.GetField(MyGd, tNotBool))
                    pie.AddClass("Selected");
            }
            else if (prop != null)
            {
                string gp = (string) MyCss[prop];
                if (!String.IsNullOrEmpty(gp))
                {
                    gp = gp.ReplaceRegex(Rx.CssFilter, "");
                    //Inform.Debug("CssTest prop={0}, value={1}, current={2}", prop, value, gp);
                    if (gp == (string) tst["value"])
                        pie.AddClass("Selected");
                }
            }
        }

        public GigMu Gmu
        {
            get { return _gmu; }
            set { _gmu = value; }
        }

        public void FillGmu()
        {
            _gmu.Css = MyCss;
        }

        public void SetSaved(bool ic)
        {
            QueSave = !ic;
        }

        #endregion

        #region Defaults

        public string MyPgBgColor
        {
            get
            {
                SlideData pg = Editor.CurrentSlide;
                return (string) (object) (((bool) (object) pg && (bool) Type.GetField(pg, "css") && (bool) pg.css["background-color"]) || (bool) (object) "rgba(0,0,0,0)");
            }
        }

        public string MyPgInvBgColor
        {
            get
            {
                Color c = Css.GetColor(MyPgBgColor);
                return c.red < 128 ? "rgba(255,255,255,1)" : "rgba(0,0,0,1)";
            }
        }

        #endregion Defaults

        public void AddCover()
        {
            CoverInner = jQuery.FromHtml("<div class='CoverInner'/>")
                .AppendTo(Element)
                ;

            Cover = jQuery.FromHtml("<div class='Cover'/>")
                .AppendTo(Element)
                .Bind("mouseenter.Gig", MaskOnEv)
                .Bind("mouseleave.Gig", MaskOffEv)
                .Bind("click.Gig", MouseGroupEv)
                .DoubleClick(DoubleClickEv)
                .Bind("contextmenu", RightClickEv)
                ;

            TheGear = jQuery.FromHtml("<div class='TheGear'/>")
                .AppendTo(Cover)
                .Hide()
                .Html("<img src='" + Uri.Img("Common/gear16.gif") + "'/>")
                .Bind("click.TheGear", GearsOnEv)
                ;

            jQuery.FromHtml("<div class='Sizer'/>")
                .AppendTo(Cover)
                .Append(jQuery.FromHtml("<img src='" + Uri.Img("Common/dragger.png") + "' style='width:100%;height:100%'/>"))
                //.Html("&hearts;")
                .MouseDown(SizeMeOnEv)
                .Hide()
                ;

            jQuery.FromHtml("<div class='Tilter'/>")
                .AppendTo(Cover)
                .Append(jQuery.FromHtml("<img src='" + Uri.Img("Common/dragger.png") + "' style='width:100%;height:100%'/>"))
                .MouseDown(TiltMeOnEv)
                .Hide()
                ;
        }

        private Dictionary MenuInstance()
        {
            Dictionary mu = new DDict()
                .Add("colors:both",
                     new DList()
                         .Add(new Dictionary("html", ColorPickerTable("text", "color"), "set", (jQueryEventHandler) PickFgColorEv))
                         .Add(new Dictionary("html", ColorPickerTable("background", "background-color"), "set", (jQueryEventHandler) PickBgColorEv))
                         .End()
                )
                .Add("color:bg",
                     new DList()
                         .Add(new Dictionary("html", ColorPickerTable("background", "background-color"), "set", (jQueryEventHandler) PickBgColorEv))
                         .End()
                )
                .Add("border",
                     new DList()
                         .Add(new Dictionary("html", "1", "set", (jQueryEventHandler) BorderSzEv, "prop", "border-width"))
                         .Add(new Dictionary("html", "2"))
                         .Add(new Dictionary("html", "3"))
                         .Add(new Dictionary("html", "4"))
                         .Add(new Dictionary("html", "5"))
                         .Add(new Dictionary("html", "6"))
                         .Add(new Dictionary("html", "7"))
                         .Add(new Dictionary("html", "8"))
                         .Add(new Dictionary("html", "9"))
                         .Add(new Dictionary("html", "10"))
                         .Add(new Dictionary("html", "11", "brk", true))
                         .Add(new Dictionary("html", RoundingPie(), "set", (jQueryEventHandler) RoundingEv, "build", (Action<GigMu>) BorderBld, "prop", false))
                         .Add(new Dictionary("html", ColorPickerTable("border color", "border-color"), "set", (jQueryEventHandler) PickBdrColorEv, "css", new Dictionary("display", "inline-block", "vertical-align", "top"), "prop", false))
                         .End()
                )
                .Add("font",
                     new DList()
                         .Add(new Dictionary("html", "bold", "set", (jQueryEventHandler) FontStlEv, "prop", "font-weight"))
                         .Add(new Dictionary("html", "no-bold", "value", "normal"))
                         .Add(new Dictionary("html", "italic", "prop", "font-style"))
                         .Add(new Dictionary("html", "no-italic", "value", "normal", "hr", true))
                         .Add(new Dictionary("html", "left", "set", (jQueryEventHandler) FontAlignEv, "prop", "text-align"))
                         .Add(new Dictionary("html", "center"))
                         .Add(new Dictionary("html", "right", "hr", true))
                         .Add(new Dictionary("html", "7", "set", (jQueryEventHandler) FontSzEv, "prop", "font-size"))
                         .Add(new Dictionary("html", "8"))
                         .Add(new Dictionary("html", "9"))
                         .Add(new Dictionary("html", "10"))
                         .Add(new Dictionary("html", "11"))
                         .Add(new Dictionary("html", "12"))
                         .Add(new Dictionary("html", "14"))
                         .Add(new Dictionary("html", "16"))
                         .Add(new Dictionary("html", "18", "brk", true))
                         .Add(new Dictionary("html", "20"))
                         .Add(new Dictionary("html", "22"))
                         .Add(new Dictionary("html", "24"))
                         .Add(new Dictionary("html", "28"))
                         .Add(new Dictionary("html", "32"))
                         .Add(new Dictionary("html", "36"))
                         .Add(new Dictionary("html", "40"))
                         .Add(new Dictionary("html", "48"))
                         .Add(new Dictionary("html", "56", "brk", true))
                         .Add(new Dictionary("html", "72"))
                         .Add(new Dictionary("html", "80"))
                         .Add(new Dictionary("html", "88"))
                         .Add(new Dictionary("html", "96"))
                         .Add(new Dictionary("html", "102"))
                         .Add(new Dictionary("html", "110"))
                         .Add(new Dictionary("html", "118", "hr", true))
                         .Add(new Dictionary("html", "Arial", "set", (jQueryEventHandler) FontFamilyEv, "prop", "font-family"))
                         .Add(new Dictionary("html", "Arial Black"))
                         .Add(new Dictionary("html", "Comic Sans Ms"))
                         .Add(new Dictionary("html", "Courier New", "brk", true))
                         .Add(new Dictionary("html", "Calibri"))
                         .Add(new Dictionary("html", "Cambria"))
                         .Add(new Dictionary("html", "Georgia"))
                         .Add(new Dictionary("html", "Tahoma", "brk", true))
                         .Add(new Dictionary("html", "Times New Roman"))
                         .Add(new Dictionary("html", "Verdana"))
                         .End()
                )
                .Add("layer",
                     new DList()
                         .Add(new Dictionary("html", "<u>f</u>ront", "set", (jQueryEventHandler) Editor.ToFrontEv /*, "align", "tab"*/))
                         .Add(new Dictionary("html", "<u>b</u>ack", "set", (jQueryEventHandler) Editor.ToBackEv))
                         .Add(new Dictionary("html", "<u>h</u>igher", "set", (jQueryEventHandler) Editor.ToHigherEv))
                         .Add(new Dictionary("html", "<u>l</u>ower", "set", (jQueryEventHandler) Editor.ToLowerEv, "brk", true))
                         .Add(new Dictionary("html", "float", "set", (jQueryEventHandler) Editor.FloatEv, "bool", "floated", "prop", "floated"))
                         .Add(new Dictionary("html", "unfloat", "set", (jQueryEventHandler) Editor.UnFloatEv, "!bool", "floated", "brk", true))
                         .Add(new Dictionary("html", "auto-stack", "set", (jQueryEventHandler) Editor.EmbeddedEv, "bool", "embedded", "prop", "embedded"))
                         .Add(new Dictionary("html", "free-form", "set", (jQueryEventHandler) Editor.UnEmbeddedEv, "!bool", "embedded", "brk", true))
                         .Add(new Dictionary("html", "auto-size", "set", (jQueryEventHandler) Editor.AutosizeEv, "bool", "autosize", "prop", "autosize"))
                         .Add(new Dictionary("html", "fixed-size", "set", (jQueryEventHandler) Editor.UnAutosizeEv, "!bool", "autosize", "hr", true))
                         .Add(new Dictionary("html", "bullet", "set", (jQueryEventHandler) Editor.FormatUlEv))
                         .Add(new Dictionary("html", "numbered", "set", (jQueryEventHandler) Editor.FormatOlEv))
                         .Add(new Dictionary("html", "plain", "set", (jQueryEventHandler) Editor.FormatPlainEv, "hr", true))
                         .End()
                )
                .Add("copy", Editor.CopyEv)
                .Add("groupify:<u>g</u>roupify", GroupifyEv)
                .Add("ungroup:un<u>g</u>roup", UngroupEv)
                .Add("zero", ZeroEv)
                .Add("link", LinkEv)
                .Add("remove", Editor.DeleteEv)
                .Add("cancel", GearsCancelEv)
                .End();
            return mu;
        }

        public void MaskOff()
        {
            MaskOffEv(null);
        }

        public void MaskOn()
        {
            MaskOnEv(null);
        }

        //
        // The .Cover class elements must remain visible so that they can trigger mouseenter events
        // When MaskOnClass is added to a group .Cover it triggers a different select color via the css sheet,
        // hence it must be removed seperatly without a .Hide()
        // Probably a cleaner way to do all this, but it is working well right now.
        //

        private void MaskOnEv(jQueryEvent e)
        {
            if (ThemeYoshi.SupressCurateEvents) return;
            jQuery.Select(".TheGear, .Sizer, .Tilter", Element.Children(".Cover")).AddClass(MaskOnClass).Show();
            Editor.FocGigEdit = this;

            if (!String.IsNullOrEmpty(MyGd.groupId))
            {
                List<GroupItem> gg = Editor.CollectGroup(e, MyGd.groupId);
                foreach (GroupItem dd in gg)
                {
                    jQuery.Select(".Cover", dd.El).Plugin<Jewl>().CopyRadius(dd.Gd.css, 2).AddClass(MaskOnClass).Show();
                    jQuery.Select(".CoverInner", dd.El).Plugin<Jewl>().CopyRadius(dd.Gd.css, 2).AddClass(MaskOnClass).Show();
                }
            }
            else
            {
                //jQuery.Select(".Cover, .CoverInner", Element).Plugin<Jewl>().CopyRadius(MyCss, 2).Show();
                Element.Children(".Cover").Plugin<Jewl>().CopyRadius(MyCss, 2).Show();
                Element.Children(".CoverInner").Plugin<Jewl>().CopyRadius(MyCss, 2).AddClass(MaskOnClass).Show();
            }
            CancelEvent(e);
        }

        private void MaskOffEv(jQueryEvent e)
        {
            //jQuery.Select(".TheGear, .Sizer, .Tilter", GigShow.PageSelectToEl).Hide();
            jQuery.Select(".Cover" + DotMaskOnClass, GigShow.PageSelectToEl).RemoveClass(MaskOnClass);
            jQuery.Select(DotMaskOnClass, GigShow.PageSelectToEl).RemoveClass(MaskOnClass).Hide();
            CancelEvent(e);
        }

        public void RightClickEv(jQueryEvent e)
        {
            if (!e.ShiftKey)
                GearsOnEv(e);
        }

        public void GearsOnEv(jQueryEvent e)
        {
            ThemeBase.ShiftKey = e.ShiftKey;
            Editor.ClearPaint();
            GigData gd = MyGd;
            ThemeYoshi.SupressCurateEvents = true;
            ThemeYoshi.EscapeOut = false;
            QueSave = false;
            _savedGig = (GigData) jQuery.Extend(true, new Dictionary(), gd);

            List<string> tabs = (List<string>) jQuery.Extend(new List<string>(), ((Dictionary) GigTypes[MyGd.type])["menus"]);
            if (!String.IsNullOrEmpty(gd.groupId))
                for (int i = 0; i < tabs.Count; i++)
                {
                    if (tabs[i] == "groupify:<u>g</u>roupify")
                        tabs[i] = "ungroup:un<u>g</u>roup";
                }

            TheGear
                .Plugin<JGig>().PopMenu(
                    new Dictionary(
                        "tabs", tabs,
                        "template", MenuInstance(),
                        "host", this,
                        "Complete", (Action) delegate
                                             {
                                                 ThemeYoshi.SupressCurateEvents = false;
                                                 if (ThemeYoshi.EscapeOut)
                                                 {
                                                     Editor.CurrentSlide.gigs[Id] = _savedGig;
                                                     Editor.ReSlideAndSave(e);
                                                 }
                                                 else if (QueSave)
                                                 {
                                                     Editor.ReSlideAndSave(e);
                                                 }
                                             }
                        ))
                ;
            CancelEvent(e);
        }

        private void GearsCancelEv(jQueryEvent e)
        {
            ThemeYoshi.EscapeOut = true;
            jQuery.Select(".VirtualGlass").Trigger("mousedown");
            CancelEvent(e);
        }

        private void SizeMeOnEv(jQueryEvent e)
        {
            Script.Literal("{0}.draggable('disable')", Element);
            jQuery.Document.Bind("mousemove.Gig", SizeMoveEv);
            jQuery.Document.Bind("mouseup.Gig", SizeMeOffEv);
            Cover.Unbind("mouseenter.Gig");
            Cover.Unbind("mouseleave.Gig");
            Cover.AddClass("RubberBand");
            MaskOnEv(e);
            CancelEvent(e);

            jQueryObject el = jQuery.FromElement(e.Target).Closest("div.Gig");
            if (el.Length > 0)
            {
                _snapToEl = el;
                _snapToW = el.GetOuterWidth();
                _snapToH = el.GetOuterHeight();
                double tilt = Math.Abs((double) Type.GetField(el[0], "tilt"));
                if (tilt > 0)
                {
                    double ww = _snapToW;
                    double hh = _snapToH;
                    double tt = el.Plugin<SnapTo>().SnapToTilt(tilt);
                    _snapToW = el.Plugin<SnapTo>().SnapToTiltW(tt, ww, hh);
                    _snapToH = el.Plugin<SnapTo>().SnapToTiltH(tt, ww, hh);
                }
                el.AddClass("GigMe");
                el.Plugin<SnapTo>().SnapCollect("div.Gig:not(.GigMe), " + GigShow.PageSelectTo);
                el.RemoveClass("GigMe");
            }
        }

        private void SizeMeOffEv(jQueryEvent e)
        {
            jQuery.Document.Unbind("mousemove.Gig");
            jQuery.Document.Unbind("mouseup.Gig");
            Cover.Bind("mouseenter.Gig", MaskOnEv);
            Cover.Bind("mouseleave.Gig", MaskOffEv);
            Cover.RemoveClass("RubberBand");
            MaskOffEv(e);
            Script.Literal("{0}.draggable('enable')", Element);
            int wd = Element.GetWidth();
            int ht = Element.GetHeight();
            if (_snapToEl.Length > 0)
            {
                int xo = Number.ParseInt(Element.GetCSS("padding-left")) + Number.ParseInt(Element.GetCSS("padding-right"));
                int yo = Number.ParseInt(Element.GetCSS("padding-top")) + Number.ParseInt(Element.GetCSS("padding-bottom"));
                int bw = Number.ParseInt(Element.GetCSS("border-right-width"))*2;
                int bh = Number.ParseInt(Element.GetCSS("border-bottom-width"))*2;
                wd = Math.Max(_snapToPos[0] - Element.GetOffset().Left - xo - bw, 20);
                ht = Math.Max(_snapToPos[1] - Element.GetOffset().Top - yo - bh, 20);
                _snapToEl.Plugin<SnapTo>().SnapDump();
                _snapToEl = _snapToNone;
                Element.Width(wd);
                if (MyGd.hasHeight)
                    Element.Height(ht);
            }
            GigData gd = MyGd;
            gd.dim = new Dimension();
            gd.dim.width = wd;
            gd.dim.height = ht;
            GigShow.MapCss(gd, Element, gd.css);
            Editor.ReSlideAndSave(e);
        }

        // TODO:
        // Needs a lot of cleanup with values combined between SizeOn, SizeOff, and SizeMove and the _snap* vars combined with those in GigShowEdit
        // Restore center ruler
        // Determine why tilted bottom points are sometimes a few pixels off
        // Determine why snapping at the far edge snaps out of the zone instead of into the zone
        // Experiment with sticky snapping where the box stays put snapped while the mouse moves until out of the zone
        //

        private void SizeMoveEv(jQueryEvent e)
        {
            int xo = Number.ParseInt(Element.GetCSS("padding-left")) + Number.ParseInt(Element.GetCSS("padding-right"));
            int yo = Number.ParseInt(Element.GetCSS("padding-top")) + Number.ParseInt(Element.GetCSS("padding-bottom"));
            int wd = Math.Max(e.PageX - Element.GetOffset().Left - xo, 20);
            int ht = Math.Max(e.PageY - Element.GetOffset().Top - yo, 20);
            int bw = Number.ParseInt(Element.GetCSS("border-right-width"))*2;
            int bh = Number.ParseInt(Element.GetCSS("border-bottom-width"))*2;
            Element.Width(wd);
            if (MyGd.hasHeight)
                Element.Height(ht);
            CancelEvent(e);
            if (_snapToEl.Length > 0)
            {
                _snapToPos = _snapToEl.Plugin<SnapTo>().SnapDim(Element.GetOffset().Left + wd + xo + bw, Element.GetOffset().Top + ht + yo + bh, Math.Round(Element.GetOuterWidth()/2), Math.Round(Element.GetOuterHeight()/2));
            }
        }

        public void ScoopPosition()
        {
            double tilt = MyGd.tilt;
            Element.Plugin<IRot>().Rotate(new Dictionary("angle", 0)); // Without easing so it happens immediatly
            GigData gd = MyGd;
            // ReSharper disable SuspiciousTypeConversion.Global
            gd.pos = (Pos) (object) Element.Position();
            //gd.off = (Pos) (object) Element.GetOffset();
            // ReSharper restore SuspiciousTypeConversion.Global
            //Inform.Debug("ScoopPosition {0}, {1}", gd.off.Left, gd.off.Top);
            Element.Plugin<IRot>().Rotate(new Dictionary("angle", tilt));
        }

        private void TiltMeOnEv(jQueryEvent e)
        {
            Script.Literal("{0}.draggable('disable')", Element);
            jQuery.Document.Bind("mousemove.Gig", TiltMoveEv);
            jQuery.Document.Bind("mouseup.Gig", TiltMeOffEv);
            Cover.Unbind("mouseenter.Gig");
            Cover.Unbind("mouseleave.Gig");
            Cover.AddClass("RubberBand");
            MaskOnEv(e);
            //jQuery.Select(".Gears", Element).Hide();
            Element.Plugin<IRot>().Rotate(new Dictionary("angle", 0));
            _xc = Element.GetOffset().Left + (Element.GetWidth()/2);
            _yc = Element.GetOffset().Top + (Element.GetHeight()/2);
            CancelEvent(e);
        }

        private void TiltMeOffEv(jQueryEvent e)
        {
            jQuery.Document.Unbind("mousemove.Gig");
            jQuery.Document.Unbind("mouseup.Gig");
            Cover.Bind("mouseenter.Gig", MaskOnEv);
            Cover.Bind("mouseleave.Gig", MaskOffEv);
            Cover.RemoveClass("RubberBand");
            MaskOffEv(e);
            Script.Literal("{0}.draggable('enable')", Element);
            MyGd.tilt = (double) Element.GetDataValue("gigTilt");
            Inform.Debug("TiltMeOff tilt = {0}", MyGd.tilt);
            Editor.CancelAndSaveAll(e);
        }

        private void TiltMoveEv(jQueryEvent e)
        {
            double deg;
            int x = e.PageX - _xc;
            int y = 0 - (e.PageY - _yc);
            deg = Math.Atan(x/y)*180/Math.PI;
            if (y < 0) deg += 180;
            else if (x < 0) deg += 360;
            AddTilt(deg);
            //Inform.Debug("deg = {0}, x = {1}, y = {2}, p.x = {3}", deg, x, y, p.Left);
            CancelEvent(e);
        }

        public void ZeroEv(jQueryEvent e)
        {
            AddTilt(0);
            MyGd.tilt = 0;
            Editor.CancelAndSaveAll(e);
        }

        public void LinkEv(jQueryEvent e)
        {
            CancelEvent(e);
            GlassOff();
            new Await()
                .AddAw(new Ask().TextAw, new Dictionary("Msg", "Enter link address", "Value", GigShowEdit.LinkHref(MyGd)))
                .AddAw(RequireResultAw, NotFail)
                .AddDx(
                    delegate(Await aw)
                    {
                        GigShowEdit.LinkifyContent(MyGd, (string) aw.Result);
                        Editor.ReSlideAndSave(e);
                    })
                .Commit();
        }

        public void GroupifyEv(jQueryEvent e)
        {
            GlassOff();
            MaskOff();
            Editor.Groupify(MyGd, true);
            Editor.CancelAndSaveAll(e);
            MaskOn();
        }

        public void UngroupEv(jQueryEvent e)
        {
            GlassOff();
            MaskOff();
            Editor.Groupify(MyGd, false);
            Editor.CancelAndSaveAll(e);
        }

        public void MouseGroupEv(jQueryEvent e)
        {
            if (e.ShiftKey)
                GroupAddEv(e);
            else if (e.AltKey)
                GroupDropEv(e);
        }

        public void GroupAddEv(jQueryEvent e)
        {
            MaskOff();
            Editor.Grouper(this, true);
            Editor.CancelAndSaveAll(e);
            MaskOn();
        }

        public void GroupStartEv(jQueryEvent e)
        {
            MyGd.groupId = Formulas.NewId;
            GroupAddEv(e);
        }

        public void GroupDropEv(jQueryEvent e)
        {
            MaskOff();
            Editor.Grouper(this, false);
            Editor.CancelAndSaveAll(e);
            MaskOn();
        }

        private static int PropKeys(jQueryObject el, int min, int max)
        {
            int i = NumberKeys(el.GetValue());
            i = Math.Max(Math.Min(Number.IsNaN(i) ? min : i, max), min);
            el.Value(i == min ? "" : i.ToString());
            return i;
        }

        private static int NumberKeys(string txt)
        {
            txt = txt.Trim();
            string t2 = "";
            for (int i = 0; i < txt.Length; i++)
            {
                int d = ")!@#$%^&*(".IndexOf(txt.CharAt(i));
                t2 += d >= 0 ? d.ToString() : txt.CharAt(i).ToString();
            }
            return Number.ParseInt(t2);
        }

        private void PaddingEv(jQueryEvent e, GigData gd)
        {
            jQueryObject el = jQuery.FromElement(e.Target);
            string cssName = el.GetAttribute("name");
            if (!(bool) el.GetDataValue("hasKeys"))
            {
                el.Data("hasKeys", true);
                el.Unbind("keydown.keys");
                el.Bind("keydown.keys", delegate(jQueryEvent e2) { PaddingKeys(e2, el, gd, cssName); });
            }
        }

        private void PaddingKeys(jQueryEvent e, jQueryObject el, GigData gd, string cssName)
        {
            Window.SetTimeout(
                delegate
                {
                    Editor.ForGroupById(e, gd.id,
                                        delegate(GroupItem gi)
                                        {
                                            string v = PropKeys(el, 0, 999) + "px";
                                            gi.Gd.css[cssName] = v;
                                            gi.Gd.css[cssName.IndexOf("-top") > 0 ? "padding-bottom" : "padding-right"] = v;
                                            gi.El.CSS(gi.Gd.css);
                                        });
                }, 50);
            QueSave = true;
        }

        private string RoundingPie()
        {
            int sz = Number.ParseInt((string) MyCss["border-radius"] ?? "0");
            string ot = "";
            ot += "<div><select class='BorderStyle' name='style' value='" + sz + "'>";
            ot += "<option value='none'>none</option>";
            ot += "<option value='solid'>solid</option>";
            ot += "<option value='dotted'>dotted</option>";
            ot += "<option value='dashed'>dashed</option>";
            ot += "<option value='double'>double</option>";
            ot += "<option value='groove'>groove</option>";
            ot += "<option value='ridge'>ridge</option>";
            ot += "<option value='inset'>inset</option>";
            ot += "<option value='outset'>outset</option>";
            ot += "</select></div>";

            ot += "<div><br>Rounding<br>";
            ot += "<input type='text' name='border-radius' size='2' value='" + sz + "'>pixels";
            ot += "</div>";

            string szx = Number.ParseInt((string) MyCss["padding"] ?? "0").ToString();
            sz = Number.ParseInt((string) (MyCss["padding-top"] ?? szx));
            ot += "<div><br>Padding vertical<br>";
            ot += "<input type='text' name='padding-top' size='2' value='" + sz + "'>pixels";
            ot += "</div>";

            sz = Number.ParseInt((string) (MyCss["padding-left"] ?? szx));
            ot += "<div><br>Padding horizontal<br>";
            ot += "<input type='text' name='padding-left' size='2' value='" + sz + "'>pixels";
            ot += "</div>";
            return ot;
        }

        private void BorderBld(GigMu gmu)
        {
            jQueryObject el = gmu.Pie.Find("select");
            el.Bind("change",
                    delegate(jQueryEvent e)
                    {
                        Type.SetField(e, "shiftKey", ThemeBase.ShiftKey);
                        Editor.ForGroupById(e, Id,
                                            delegate(GroupItem gi)
                                            {
                                                Inform.Debug("BorderBld shiftKey={0} id={1}", e.ShiftKey, gi.Gd.id);
                                                string stl = el.GetValue();
                                                gi.Gd.css["border-style"] = stl;
                                                Css.ResetCss(gi.El);
                                                gi.El.CSS(gi.Gd.css);
                                            });
                        QueSave = true;
                    }
                );
            el.Value((string) MyCss["border-style"] ?? "none");
        }

        private void RoundingEv(jQueryEvent e)
        {
            jQueryObject el = jQuery.FromElement(e.Target);
            el.Closest(".Pie").RemoveClass("Selected");
            el.Focus();

            Editor.ForGroupById(e, MyGd.id,
                                delegate(GroupItem gi)
                                {
                                    string n = el.GetAttribute("name");
                                    if (n != null && n.IndexOf("padding") != -1)
                                        PaddingEv(e, gi.Gd);
                                    else if (n != null && n == "style")
                                        return;
                                    if (!(bool) el.GetDataValue("hasKeys"))
                                    {
                                        el.Data("hasKeys", true);
                                        el.Unbind("keydown.keys");
                                        el.Bind("keydown.keys", delegate(jQueryEvent e2) { RoundingKeys(e2, el, gi.Gd); });
                                    }
                                });
        }

        private void RoundingKeys(jQueryEvent e, jQueryObject el, GigData gd)
        {
            Window.SetTimeout(
                delegate
                {
                    Editor.ForGroupById(e, gd.id,
                                        delegate(GroupItem gi)
                                        {
                                            string v = PropKeys(el, 0, 999) + "px";
                                            gi.Gd.css["border-radius"] = v;
                                            gi.Gd.css["-moz-border-radius"] = v;
                                            gi.Gd.css["-webkit-border-radius"] = v;
                                            Css.ResetCss(gi.El);
                                            GigShow.MapCss(gi.Gd, gi.El, gi.Gd.css);
                                            //Inform.Debug("PickColorGv input click color={0}", color);
                                        });
                }, 50);
            QueSave = true;
        }

        private string ColorPickerTable(string label, string colorName)
        {
            string ot = "";
            ot += "<div title='transparent'>" + label + " ";
            ot += "<span class='Transparent' title='none'>x</span>";
            ot += "<span class='Transparent' title='transparent'>&#9744;</span>";
            ot += "</div>";
            ot += (string) Await.Files["ColorPickerTable"];
            ot += "<div class='Opaque'>Opaque <input type='text' size='2' class='" + colorName + "' value='" + (Css.AlphaPercent((string) MyCss[colorName]) ?? "") + "'>%</div>";
            return ot;
        }

        private void ColorOpacityKeys(jQueryEvent e, string colorName)
        {
            jQueryObject el = jQuery.FromElement(e.Target);
            Window.SetTimeout(
                delegate
                {
                    Editor.ForGroupById(e, MyGd.id,
                                        delegate(GroupItem gi)
                                        {
                                            int cv = PropKeys(el, 0, 100);
                                            Dictionary css = gi.Gd.css;
                                            Color c = Css.GetColor((string) css[colorName]);
                                            c.opacity = (double) cv/100;
                                            string color = c.ToString();
                                            css[colorName] = color;
                                            Css.ResetCss(gi.El);
                                            gi.El.CSS(css);
                                            //Inform.Debug("PickColorGv input click color={0}", color);
                                        });
                }, 50);
            QueSave = true;
        }

        private void PickColorGv(jQueryEvent e, string colorName)
        {
            Editor.ForGroupById(e, MyGd.id, delegate(GroupItem gi) { GigShowEdit.GigEditById(gi.Gd.id).PickColorEv(e, colorName); });
        }

        public void PickColorEv(jQueryEvent e, string colorName)
        {
            jQueryObject el = jQuery.FromElement(e.Target);
            string color = el.GetAttribute("title");
            Dictionary css = MyGd.css;
            if (el.Is("input[type=text]"))
            {
                if (!(bool) el.GetDataValue("hasKeys"))
                {
                    el.Data("hasKeys", true);
                    el.Unbind("keydown.keys");
                    el.Bind("keydown.keys", delegate(jQueryEvent e2) { ColorOpacityKeys(e2, colorName); });
                }
                el.Focus();
            }
            else if (color != null)
            {
                if (color != "none")
                {
                    Color c1 = Css.GetColor((string) css[colorName]);
                    Color c2 = Css.GetColor(color);
                    c2.opacity = color == "transparent" ? 0 : c1.opacity;
                    css[colorName] = c2.ToString();
                    SetOpacity(MyGd, colorName, c2.opacity == 0 && color != "transparent" ? 1 : c2.opacity);
                }
                else
                {
                    css.Remove(colorName);
                }
                Css.ResetCss(Element);
                Element.CSS(css);
                QueSave = true;
            }
            CancelEvent(e);
        }

        private void PickBgColorEv(jQueryEvent e)
        {
            PickColorGv(e, "background-color");
        }

        public void PickFgColorEv(jQueryEvent e)
        {
            PickColorGv(e, "color");
        }

        private void PickBdrColorEv(jQueryEvent e)
        {
            Editor.ForGroupById(e, MyGd.id,
                                delegate(GroupItem gi)
                                {
                                    Dictionary css = gi.Gd.css;
                                    GigShowEdit.GigEditByEl(gi.El).PickColorEv(e, "border-color");
                                    css["border-style"] = BdrStyle(gi.Gd);
                                    css["border-width"] = BdrWidth(gi.Gd);
                                    Css.ResetCss(gi.El);
                                    gi.El.CSS(css);
                                });
            QueSave = true;
            CancelEvent(e);
        }

        [AlternateSignature]
        private extern string BdrStyle(GigData gd);

        private string BdrStyle(GigData gd, string style)
        {
            Dictionary css = gd.css;
            string stl = style ?? (string) css["border-style"] ?? "solid";
            stl = stl == "none" ? "solid" : stl;
            jQuery.Select(".BorderStyle", Gmu.Pad).Value(stl);
            if (GetOpacity(gd, "border-color") == 0)
                SetOpacity(gd, "border-color", 1);
            return stl;
        }

        [AlternateSignature]
        private extern string BdrWidth(GigData gd);

        private string BdrWidth(GigData gd, string bw)
        {
            string w = bw ?? Css.BorderWidth(gd.css, 1).ToString();
            string v = Number.ParseInt(w).ToString();
            jQuery.Select(".border-width", Gmu.Pad).Filter(delegate { return jQuery.This.GetHtml() == v; }).AddClass("Selected");
            return v + "px";
        }

        private double GetOpacity(GigData gd, string name)
        {
            return Css.GetColor((string) gd.css[name] ?? Css.White).opacity;
        }

        private void SetOpacity(GigData gd, string name, double op)
        {
            Color c = Css.GetColor((string) gd.css[name]);
            c.opacity = op;
            gd.css[name] = c.ToString();
            jQuery.Select(".Opaque ." + name, Gmu.Pad).Value((c.opacity*100).ToString());
        }

        private void BorderSzEv(jQueryEvent e)
        {
            Editor.ForGroupById(e, MyGd.id,
                                delegate(GroupItem gi)
                                {
                                    int sz = Number.ParseInt((string) (jQuery.FromElement(e.Target).GetDataValue("value") ?? "1"));
                                    //Inform.Debug("Setting BorderSzEv sz = {0}, from {1}", sz, jQuery.FromElement(e.Target).GetDataValue("value"));
                                    Dictionary css = gi.Gd.css;
                                    css["border-color"] = css["border-color"] ?? MyPgInvBgColor;
                                    css["border-style"] = BdrStyle(gi.Gd);
                                    css["border-width"] = BdrWidth(gi.Gd, sz + "px");
                                    gi.El.CSS(css);
                                });
            QueSave = true;
            CancelEvent(e);
        }

        private void FontSzEv(jQueryEvent e)
        {
            Editor.ForGroupById(e, MyGd.id,
                                delegate(GroupItem gi)
                                {
                                    int sz = Number.ParseInt((string) jQuery.FromElement(e.Target).GetDataValue("value"));
                                    Dictionary css = gi.Gd.css;
                                    css["font-size"] = sz + "pt";
                                    gi.El.CSS(css);
                                });
            QueSave = true;
            CancelEvent(e);
        }

        private void FontFamilyEv(jQueryEvent e)
        {
            Editor.ForGroupById(e, MyGd.id,
                                delegate(GroupItem gi)
                                {
                                    string font = (string) jQuery.FromElement(e.Target).GetDataValue("value");
                                    Dictionary css = gi.Gd.css;
                                    css["font-family"] = font;
                                    gi.El.CSS(css);
                                });
            QueSave = true;
            CancelEvent(e);
        }

        private void FontStlEv(jQueryEvent e)
        {
            Editor.ForGroupById(e, MyGd.id,
                                delegate(GroupItem gi)
                                {
                                    string stl = (string) jQuery.FromElement(e.Target).GetDataValue("value");
                                    Dictionary css = gi.Gd.css;
                                    css[Gmu.Pdp.prop] = stl;
                                    gi.El.CSS(css);
                                });
            QueSave = true;
            CancelEvent(e);
        }

        private void FontAlignEv(jQueryEvent e)
        {
            Editor.ForGroupById(e, MyGd.id,
                                delegate(GroupItem gi)
                                {
                                    string stl = (string) jQuery.FromElement(e.Target).GetDataValue("value");
                                    Dictionary css = gi.Gd.css;
                                    css["text-align"] = stl;
                                    gi.El.CSS(css);
                                });
            QueSave = true;
            CancelEvent(e);
        }

        private void DoubleClickEv(jQueryEvent e)
        {
            jQueryEventHandler dbk = (jQueryEventHandler)Element.GetDataValue("doubleclick");
            if (dbk != null)
            {
                dbk(e);
            }
            else
            {
                EditTextEv(e);
            }
        }

        private void EditTextEv(jQueryEvent e)
        {
            bool escape = false;
            jQueryObject el = Element;
            GigShowConfig cfg = GigShow.CssMap[MyGd.type];
            if (cfg == null || !cfg.doubleclick)
            {
                CancelEvent(e);
                return;
            }
            bool isList = !String.IsNullOrEmpty(MyGd.listType);
            ThemeYoshi.SupressCurateEvents = true;
            jQueryObject ctt = el.Children().First().Find(cfg.inner).First();
            Editor.Muffel();
            el.Find(".Cover").Hide();
            Dictionary css = MyGd.css;
            Dictionary css2 = (Dictionary) jQuery.Extend(new Dictionary(), css);
            css2.Remove("margin");
            css2.Remove("padding");
            css2.Remove("border-style");
            css2.Remove("border-width");
            css2.Remove("padding-top");
            css2.Remove("padding-left");
            css2.Remove("padding-right");
            css2.Remove("padding-bottom");
            css2["overflow"] = "hidden";
            if (cfg.css) // If css is being applied to inner, as in form elements
            {
                int pv = Css.PaddingTop(css, DeefCss["padding-top"]);
                int ph = Css.PaddingLeft(css, DeefCss["padding-left"]);
                css2["color"] = ctt.GetCSS("color");
                css2["background-color"] = Css.RealBgColor(ctt);
                jQueryPosition p = ctt.GetOffset();
                jQuery.Extend(css2, new Dictionary("top", p.Top, "left", p.Left, "width", ctt.GetInnerWidth() - ph - ph, "height", ctt.GetInnerHeight() - pv - pv));
                jQuery.Extend(css2, new Dictionary("padding-left", ph, "padding-right", ph, "padding-top", pv, "padding-bottom", 0));
            }
            else
            {
                css2.Remove("border-radius");
                css2.Remove("-moz-border-radius");
                css2.Remove("-webkit-border-radius");
                css2["color"] = el.GetCSS("color");
                css2["background-color"] = Css.RealBgColor(el);
                jQueryPosition p = ctt.GetOffset();
                jQuery.Extend(css2, new Dictionary("top", p.Top - 1, "left", p.Left - 2, "width", ctt.GetInnerWidth() + 4, "height", ctt.GetInnerHeight() + 2));
                jQuery.Extend(css2, new Dictionary("padding-left", 2, "padding-right", 2, "padding-top", 1, "padding-bottom", 1));
            }
            if (cfg.inner == "button")
                css2["text-align"] = "center";

            string wrap = isList ? "off" : "soft";
            jQueryObject tx = jQuery.FromHtml("<textarea class='GigEditText AboveHider' wrap='" + wrap + "' style='position:absolute;padding:0;margin:0;border: 0px none transparent'/>");

            // Creep prevention requires change of 10px to auto-resize box after edit box size change.
            int sw = el.GetInnerWidth();
            int sh = el.GetInnerHeight();
            string value = ctt.Plugin<Jewl>().GetContent();

            Glass(delegate { tx.Blur(); }).CSS(new Dictionary("background-color", "rgba(0,0,0,.25)"));

            //Inform.Debug("Edit value for [{0}] = {1}", cfg.inner, value);
            //Inform.Dump(css2, "css");

            Dictionary<string, KeyAction> editKeys = new Dictionary(
                "13:s",
                (KeyAction) delegate(jQueryEvent ek)
                            {
                                CancelEvent(ek);
                                GlassOff();
                            },
                "27:", /*esc*/
                (KeyAction) delegate(jQueryEvent ek)
                            {
                                CancelEvent(ek);
                                escape = true;
                                GlassOff();
                            },
                "9:", /*tab*/
                (KeyAction) delegate(jQueryEvent ek)
                            {
                                CancelEvent(ek);
                                Helpers.InsertText(tx, "\t");
                            }
                );

            tx
                .AppendTo(Document.Body)
                .CSS(css2)
                .Plugin<Jewl>().FValue(GigParse.HtmlToList(value, MyGd.listType))
                .Bind("blur.editev",
                      delegate
                      {
                          ThemeYoshi.SupressCurateEvents = false;
                          Trigger("TabLineCounter", false);
                          GigShow.MapCss(MyGd, el, css);
                          ctt.Show();
                          int w = tx.GetInnerWidth();
                          int h = tx.GetInnerHeight();
                          if (w >= sw + 10)
                              el.CSS(new Dictionary("width", w));
                          if (h >= sh + 10)
                              el.CSS(new Dictionary("height", h));
                          // ReSharper disable AccessToModifiedClosure
                          if (!escape)
                              // ReSharper restore AccessToModifiedClosure
                          {
                              string txt = GigParse.ListToHtml(tx.Plugin<Jewl>().GetFEditString(), MyGd.listType);
                              txt = String.IsNullOrEmpty(txt.Trim()) ? YourText : txt;
                              jQueryObject elx = el.Find(cfg.inner);
                              elx.Plugin<Jewl>().SetContent(txt);
                              MyGd.html = ReplaceText(MyGd.html, txt);
                          }

                          ctt.Show();
                          el.Find(".Cover").Show();
                          el.Find(".CoverInner").Show();
                          tx.Unbind(".editev").Remove();

                          //Inform.Debug("Edit outer html = {0}", MyGd.html);
                          Editor.ReSlideAndSave(e);
                          GlassOff(true);

                          Editor.Listen();
                      })
                .Bind("keydown.editev",
                      delegate(jQueryEvent e2)
                      {
                          string k = Keys.DoKeys(e2, editKeys);
                          if (k == null)
                              return;

                          if (isList)
                          {
                              if (e2.Which == 13)
                              {
                                  //Window.SetTimeout(delegate { tx.Value(tx.GetValue().ReplaceRegex((RegularExpression) Script.Literal(@"/[\n\r\t]+/g"), "\n\t")); }, 1);
                                  Window.SetTimeout(delegate { tx.Value(tx.GetValue().ReplaceRegex((RegularExpression) Script.Literal(@"/[\n]([^\t])|\n$/g"), "\n\t$1")); }, 1);
                              }
                              else if (e2.Which == 8)
                              {
                                  Window.SetTimeout(delegate { tx.Value(tx.GetValue().ReplaceRegex((RegularExpression) Script.Literal(@"/[\n]([^\t])|\n$/g"), "$1")); }, 1);
                              }
                          }
                      })
                .Click().Focus().Plugin<Jewl>().CarotToEnd()
                ;
            if (tx.GetValue() == YourText)
                tx.Value("");

            //if (MyGd.autosize)
            TextAreaExpander(tx);

            ctt.Hide();

            if (isList)
                Trigger("TabLineCounter", tx);

            CancelEvent(e);
        }

        public static void TextAreaExpander(jQueryObject el)
        {
            el.Bind("keydown.editev paste.editev cut.editev", delegate { Window.SetTimeout(delegate { ResizeEl(el); }, 1); });
            ResizeEl(el);
        }

        public static void ResizeEl(jQueryObject el)
        {
            // Don't know why, but setting Height(0) works here and setting Height("") works in GigShowEdit.Autosize()
            // but not visa versa ... go figure huh?
            int ht = el.Height(0)[0].ScrollHeight;
            el.Height(ht);
            //Inform.Debug("ResizeEl ht={0}, lh={1}", ht, lineHeight);
        }

        [AlternateSignature]
        public static extern string ReplaceText(string html, string content);

        public static string ReplaceText(string html, string content, string selector)
        {
            selector = selector ?? DotGigContentClassName;
            jQueryObject el = jQuery.FromHtml(html).AppendTo(Document.Body);
            el.Find(selector).Plugin<Jewl>().SetContent(content);
            string ot = OuterHtml(el);
            el.Remove();
            return ot;
        }

        public static jQueryObject Domify(string html)
        {
            return jQuery.FromHtml(html).AppendTo(Document.Body);
        }

        public static jQueryObject DomifyContent(string html, string selector)
        {
            jQueryObject el = Domify(html);
            jQueryObject cel = jQuery.Select(selector, el).AppendTo(Document.Body);
            el.Remove();
            return cel;
        }

        public static jQueryObject DomContent(jQueryObject el)
        {
            return el.Find(DotGigContentClassName);
        }

        [AlternateSignature]
        public extern GigEdit DelayScoopSize(string url);

        public GigEdit DelayScoopSize(string url, int endTime)
        {
            endTime = Script.IsValue(endTime) ? endTime : (new Date()).GetTime() + 60000;
            int h = Element.GetHeight();
            if (h > 0)
            {
                GigData gd = MyGd;
                gd.dim = new Dimension();
                gd.dim.width = Element.GetWidth();
                gd.dim.height = h;
                ImageManager.UpdateImageDataAw(Await.AsyncAw, url);
                SaveAll();
            }
            else if ((new Date()).GetTime() < endTime)
                new Await().Sleep(13).AddDx(delegate { DelayScoopSize(url, endTime); }).Commit();
            return this;
        }

        public GigEdit SaveAll()
        {
            Editor.SaveAllAw(Await.AsyncAw);
            return this;
        }

        //private GigData Scoop(jQueryObject el)
        //{
        //    string id = el.GetAttribute("id");
        //    GigData gd = SlideGigs[id] ?? new GigData(Editor.PageSelectTo);
        //    //gd.tilt = Script.IsValue(el.GetDataValue("gigTilt")) ? (double)el.GetDataValue("gigTilt") : 0;
        //    //gd.id = id;
        //    //gd.type = (string)el.GetDataValue("gigType");
        //    //gd.hasHeight = (bool)el.GetDataValue("gigHasHeight");
        //    gd.pos = (Pos)(object)el.Position();
        //    gd.off = (Pos)(object)el.GetOffset();
        //    gd.dim = new Dimension();
        //    gd.dim.width = el.GetWidth();
        //    gd.dim.height = el.GetHeight();
        //    //gd.classNames = (el.GetAttribute("class") ?? "").ReplaceRegex(RxDraggable, "");
        //    gd.selecTo = el.Parent().Plugin<Jewl>().SelecTo();
        //    //gd.html = OuterHtml(el.Children().First());
        //    gd.css = gd.css ?? new Dictionary();
        //    return gd;
        //}

        public override void Draggable(Dictionary opt, jQueryEventHandler doneFn)
        {
            Element.Plugin<Jewl>().Draggable(opt);
            Element.Bind("dragstop.Gig", doneFn);
            //return this;
        }
    }
}